﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using XRpgLibrary;
using XRpgLibrary.GraphicsClasses;
using XRpgLibrary.TileEngine;
using XRpgLibrary.ExtensionMethods;

namespace XRpgLibrary.InterfaceClasses
{
    public class ConversationBox : BaseMenuComponent, IGameDrawableMenu, IGameUpdateableMenu
    {
        const int DEFAULT_WIDTH = 960;
        const int DEFAULT_HEIGHT = 320;
        private int lineOffset = 0;
        private string wrappedText = string.Empty;
        public Vector4 Padding = new Vector4(16, 16, 16, 16);
        private Vector2 textStartPosition;
        private float maxLineWidth = -1f;
        private float maxTextHeight = -1f;
        private int maxTextLines = -1;
        private string[] lines;
        private Rectangle downArrowRectangle;
        private Rectangle upArrowRectangle;


        public string Text { get; set; }

        public string WrappedText
        {
            get
            {
                if (String.IsNullOrEmpty(wrappedText))
                    wrappedText = WrapText(Text);

                return wrappedText;
            }
        }
        
        private Vector2 TextStartPosition
        {
            get
            {
                if (textStartPosition.X == 0)
                {
                    textStartPosition = new Vector2(
                        MenuRectangle.X + Padding.X,
                        MenuRectangle.Y + Padding.Y 
                        );
                }

                return textStartPosition;
            }
            set
            {
                textStartPosition = value;
            }
        }

        private float MaxLineWidth
        {
            get
            {
                if (maxLineWidth < 0)
                    maxLineWidth = MenuRectangle.Width - Padding.X - Padding.W;
                

                return maxLineWidth;
            }
            set
            {
                maxLineWidth = value;
            }
        }

        private float MaxTextHeight
        {
            get
            {
                if (maxTextHeight < 0)
                    maxTextHeight = MenuRectangle.Height - Padding.Y - Padding.Z;


                return maxTextHeight;
            }
            set
            {
                maxTextHeight = value;
            }
        }

        private int MaxTextLines 
        {
            get
            {
                if (maxTextLines < 0)
                    maxTextLines = (int)(MaxTextHeight / MenuFont.LineSpacing);

                return maxTextLines;
            }
            set
            {
                maxTextHeight = value;
            }
        }

        private string[] Lines
        {
            get
            {
                if (lines == null)
                    lines = WrappedText.Split('\n');

                return lines;
            }
        }

        private int MaxLineOffset
        {
            get
            {
                return Lines.Length - MaxTextLines - 1;
            }
        }

        private Rectangle DownArrowRectangle
        {
            get
            {
                if (downArrowRectangle.Width == 0)
                    downArrowRectangle = new Rectangle(
                        MenuRectangle.X + MenuRectangle.Width - BORDER_WIDTH,
                        MenuRectangle.Y + MenuRectangle.Height - BORDER_WIDTH,
                        BORDER_WIDTH,
                        BORDER_WIDTH);

                return downArrowRectangle;
            }
        }

        private Rectangle UpArrowRectangle
        {
            get
            {
                if (upArrowRectangle.Width == 0)
                    upArrowRectangle = new Rectangle(
                        MenuRectangle.X + MenuRectangle.Width - BORDER_WIDTH,
                        MenuRectangle.Y + BORDER_WIDTH,
                        BORDER_WIDTH,
                        BORDER_WIDTH);

                return upArrowRectangle;
            }
        }

        public ConversationBox(RpgGame game, string text, int x, int y, int width, int height, Vector4 padding)
            : base(game, new Rectangle(x, y, width, height), true)
        {
            Text = text;
            Padding = padding;
        }

        public ConversationBox(RpgGame game, string text, int x, int y, int width, int height)
            : base(game, new Rectangle(x, y, width, height), true)
        {
            Text = text;
        }


        public ConversationBox(RpgGame game, string text, MenuPlacementX x, MenuPlacementY y, int width, int height)
            : base(game, x, y, width, height, true)
        {
            Text = text;
        }

        public ConversationBox(RpgGame game, string text, MenuPlacementX x, MenuPlacementY y)
            : base(game, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT, true)
        {
            Text = text;
        }

        public ConversationBox(RpgGame game, string text)
            : base(game, MenuPlacementX.Center, MenuPlacementY.Center, DEFAULT_WIDTH, DEFAULT_HEIGHT, true)
        {
            Text = text;
        }


        public string WrapText(string text)
        {
            StringBuilder sb = new StringBuilder();
            float lineWidth;
            float spaceWidth = MenuFont.MeasureString(" ").X;
            string prepend = string.Empty;
            Vector2 size;

            string[] paragraphs = text.Split('\n');
            foreach (string paragraph in paragraphs)
            {
                lineWidth = 0f;
                string[] words = paragraph.Split(' ');
                
                foreach (string word in words)
                {
                    size = MenuFont.MeasureString(word);

                    prepend = (lineWidth + size.X < MaxLineWidth) ? string.Empty : "\n";
                
                    sb.Append(prepend + word + " ");
                    
                    if (String.IsNullOrEmpty(prepend))
                        lineWidth += size.X + spaceWidth;
                    else
                        lineWidth = size.X + spaceWidth;
                }

                sb.Append("\n");
            }

            return sb.ToString();
        }

        public override void Draw(GameTime gameTime, Camera camera)
        {
            this.Draw(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime, null);

            if (Visible && Enabled)
            {
                DrawLines();

                DrawArrows();
            }
        }

        private void DrawArrows()
        {
            if (MaxTextLines < Lines.Length && lineOffset < MaxLineOffset)
                spriteBatch.Draw(
                    MenuBorderSourceTexture,
                    DownArrowRectangle,
                    new Rectangle(BORDER_WIDTH * 4, 0, BORDER_WIDTH, BORDER_WIDTH),
                    Color.White, 
                    0,
                    new Vector2(
                        BORDER_WIDTH / 2, 
                        BORDER_WIDTH / 2),
                    SpriteEffects.FlipVertically,
                    0);

            if (MaxTextLines < Lines.Length && lineOffset > 0)
                spriteBatch.Draw(
                    MenuBorderSourceTexture,
                    UpArrowRectangle,
                    new Rectangle(BORDER_WIDTH * 4, 0, BORDER_WIDTH, BORDER_WIDTH),
                    Color.White);
        }

        private void DrawLines()
        {
            for (int i = lineOffset, lineDisplayIndex = 0, cnt = Lines.Length; i < cnt; i++)
            {
                if (i > lineOffset + MaxTextLines - 1) break;

                spriteBatch.DrawString(
                    MenuFont,
                    Lines[i],
                    @"(\**?\*)",
                    new Vector2(TextStartPosition.X, TextStartPosition.Y + MenuFont.LineSpacing * lineDisplayIndex),
                    Color.White, 
                    Color.Red);
                lineDisplayIndex++;
            }
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            //if (InputHandler.KeyReleased(GameCommands.ActivateMainMenu))
            //    Kill();

            if (MaxTextLines < Lines.Length)
            {
                if (InputHandler.KeyPressed(Keys.Down))
                {
                    lineOffset++;
                    if (lineOffset > MaxLineOffset)
                        lineOffset--;
                }
                else if (InputHandler.KeyPressed(Keys.Up))
                {
                    lineOffset--;
                    if (lineOffset < 0)
                        lineOffset = 0;
                }
            }
        }
    }
}
